#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "err.hpp"

// V2版本：
// 功能：基于多进程的多人聊天室
// 核心：多进程同时读写

namespace ns_server
{
    class TcpServer
    {
        static const uint16_t default_port = 8080;
        static const int backlog = 32; // TODO
    public:
        TcpServer(uint16_t port = default_port)
            : port_(port), quit_(true)
        {
        }

        ~TcpServer()
        {
        }

        void InitServer()
        {
            // 初始化服务器
            listen_sock_ = socket(AF_INET, SOCK_STREAM, 0); // 基于IPV4的流式数据传输
            if (listen_sock_ == -1)
            {
                std::cerr << "Create Sock Fail: " << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }

            // 创建addr结构体（包含自己的端口号和IP信息）
            struct sockaddr_in local;
            memset(&local, 0, sizeof local);
            local.sin_family = AF_INET;
            local.sin_port = htons(port_);
            local.sin_addr.s_addr = INADDR_ANY; // 可以绑定任意ip

            // 绑定
            if (bind(listen_sock_, (struct sockaddr *)&local, sizeof local) == -1)
            {
                std::cerr << "Bind Sock Fail: " << strerror(errno) << std::endl;
                exit(BIND_ERR);
            }

            // 监听
            if (listen(listen_sock_, backlog) == -1)
            {
                std::cerr << "Listen Sock Fail: " << strerror(errno) << std::endl;
                exit(LISTEN_ERR);
            }

            std::cout << "socket bind listen success!" << std::endl;
        }

        void service(const int &sock, const struct sockaddr_in &client)
        {
            // 流式数据传输，可以使用文件操作相关接口

            // 处理数据（打印）
            std::string ip = inet_ntoa(client.sin_addr);
            uint16_t port = ntohs(client.sin_port);
            std::string who = "Client [" + ip + "-" + std::to_string(port) + "]";

            char buff[1024];
            while (true)
            {
                // 从客户端读取数据
                int n = read(sock, buff, sizeof(buff) - 1);
                if (n > 0)
                {
                    buff[n] = '\0';

                    std::cout << who << " >>" << buff << std::endl;

                    // 回响数据
                    write(sock, buff, strlen(buff));
                }
                else if (n == 0)
                {
                    // 写端关闭，读到0了
                    std::cout << who << " quit, Me too" << std::endl;
                    break;
                }
                else
                {
                    // 读取异常
                    std::cerr << "Read Error: " << strerror(errno) << std::endl;
                    break;
                }
            }

            close(sock);
        }

        void StartServer()
        {
            // 直接屏蔽 SIG_CHLD 信号
            // signal(SIGCHLD, SIG_IGN);   //父进程不等子进程（推荐）

            quit_ = false; // 服务器运行，不退出
            while (!quit_)
            {
                // 连接
                struct sockaddr_in client; // 客户端信息
                socklen_t len = sizeof(client);
                int sock = accept(listen_sock_, (struct sockaddr *)&client, &len);
                if (sock == -1)
                {
                    std::cerr << "Accept Sock Fail: " << strerror(errno) << std::endl;
                    exit(ACCEPT_ERR);
                }
                std::cout << "Link Success! " << sock << " from " << listen_sock_ << std::endl;

                // 创建子进程，执行读写任务
                pid_t id = fork();

                if (id == 0)
                {
                    // // 子进程，执行任务
                    // close(listen_sock_);
                    // service(sock, client);
                    // exit(0);    //正常退出

                    // 让孙子进程执行任务，子进程被父进程正常回收
                    if (fork() > 0)
                        exit(0); // 子进程退出
                    service(sock, client);
                    exit(0); // 被 bash 领养，由 bash 负责（仍然属于 父进程 进程组）
                }
                else if (id < 0)
                {
                    close(sock);
                    continue;
                }
                else
                {
                    // 父进程
                    // 关闭套接字
                    close(sock);

                    // //等待子进程退出
                    // // pid_t ret = waitpid(id, nullptr, 0);    //照样是阻塞的
                    // pid_t ret = waitpid(id, nullptr, WNOHANG);    //非阻塞式等待（不推荐）

                    // 等待子进程退出
                    pid_t ret = waitpid(id, nullptr, 0);    //正常回收子进程
                    if (ret == id)
                        std::cout << "wait child " << id << " success" << std::endl;
                }
            }
        }

    private:
        int listen_sock_; // 监听套接字
        uint16_t port_;   // 端口号
        bool quit_;       // 退出状态
    };
}